package pl.com.qapps.datastore.objectify;

import pl.com.qapps.datastore.Datastore;

import com.googlecode.objectify.Objectify;
import com.googlecode.objectify.ObjectifyFactory;

/**
 * It is a simple container for objectify factory which must be set first, but
 * only once. Call for factory() will return IllegalStateException if no
 * Datastore is initialized first or it has been done so before. You can write
 * your own class to help you manage your ObjectifyFactory/ies the way it suits
 * you. Also this class provides convenient methods for specifiing custom data
 * source.
 * 
 * @author qba
 * 
 */
public class OfyService {

	private OfyService() {
	}

	/** Static instance */
	private static ObjectifyFactory factory;

	/**
	 * A shorthand for init(new CustomObjectifyFactory(Datastore))
	 * 
	 * @param ds
	 *            non null
	 * @throws IllegalStateException
	 *             if ds is {@code null}
	 * @throws IllegalArgumentException
	 *             if factory has been already set
	 */
	public static synchronized void init(Datastore ds)
			throws IllegalStateException, IllegalArgumentException {
		if (ds == null)
			throw new IllegalArgumentException("ds cannot be null");

		init(new OfyFactory(ds));
	}

	/**
	 * Initialize this static container with your {@link ObjectifyFactory}. You
	 * can pass {@link CustomObjectofyFactory} initialized with chosen
	 * {@link Datastore} implementation or simply pass the original
	 * {@link ObjectifyFactory}.
	 * 
	 * @param factory
	 * @throws IllegalStateException
	 *             if theFactory is {@code null}
	 * @throws IllegalArgumentException
	 *             if factory has been already set
	 */
	public static synchronized void init(ObjectifyFactory factory)
			throws IllegalStateException, IllegalArgumentException {

		if (OfyService.factory != null)
			throw new IllegalStateException("already initialized");
		if (factory == null)
			throw new IllegalArgumentException("factory cannot be null");

		OfyService.factory = factory;
	}

	/**
	 * Remember to initialize the factory first calling init() variants.
	 * 
	 * @return the {@link ObjectifyFactory} instance held by this container
	 * @throws IllegalStateException
	 *             if no factory has been initialized first
	 */
	public static ObjectifyFactory factory() throws IllegalStateException {

		if (factory == null)
			throw new IllegalStateException("no factory has been set yet");

		return factory;
	}

	//
	// All static methods simply pass-through to the singleton factory
	//

	/** @see ObjectifyFactory#begin() */
	public static Objectify begin() {
		return factory().begin();
	}

	/** @see ObjectifyFactory#register(Class) */
	public static void register(Class<?> clazz) {
		factory().register(clazz);
	}

}
